package com.pdg.android.splorr.data;

import java.util.Iterator;

import com.pdg.android.splorr.Utilities;
import com.pdg.android.splorr.data.baseclasses.DataClientWithItems;
import com.pdg.android.splorr.data.enums.CloseDoorActionResult;
import com.pdg.android.splorr.data.enums.DoorState;
import com.pdg.android.splorr.data.enums.DropItemActionResult;
import com.pdg.android.splorr.data.enums.GameState;
import com.pdg.android.splorr.data.enums.MoveAheadResult;
import com.pdg.android.splorr.data.enums.OpenDoorActionResult;
import com.pdg.android.splorr.data.enums.PlayerState;
import com.pdg.android.splorr.data.enums.RoomDirection;
import com.pdg.android.splorr.data.enums.SearchForItemsResult;
import com.pdg.android.splorr.data.enums.SearchWallActionResult;
import com.pdg.android.splorr.data.enums.TakeItemActionResult;
import com.pdg.android.splorr.data.enums.UnlockDoorActionResult;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

public class Player extends DataClientWithItems<Game,PlayerItem,Player>{
	
	private static final String KEY_BASE = "player_";

	private static final String SUBKEY_STATE = "state";
	private static final String SUBKEY_X = "x";
	private static final String SUBKEY_Y = "y";
	private static final String SUBKEY_FACING = "facing";
		
	private static final PlayerState DEFAULT_STATE = PlayerState.ROOM;
	private static final int DEFAULT_X = 0;
	private static final int DEFAULT_Y = 0;
	private static final RoomDirection DEFAULT_FACING = RoomDirection.NORTH;

	private static final String SUBKEY_ITEM_COUNT = "item_count";

	private static final int DEFAULT_ITEM_COUNT = 0;

	private RoomDirection facing;
	private PlayerState state;
	private int y;
	private int x;

	public Player(Game theData) {
		super(theData);
	}

	@Override
	protected void onLoad(SharedPreferences thePreferences) {
		setState(PlayerState.valueOf(thePreferences.getString(getSubKey(SUBKEY_STATE), DEFAULT_STATE.name())));
		setFacing(RoomDirection.valueOf(thePreferences.getString(getSubKey(SUBKEY_FACING), DEFAULT_FACING.toString())));
		setX(thePreferences.getInt(getSubKey(SUBKEY_X), DEFAULT_X));
		setY(thePreferences.getInt(getSubKey(SUBKEY_Y), DEFAULT_Y));
		getItems().clear();
		int itemCount = thePreferences.getInt(getSubKey(SUBKEY_ITEM_COUNT), DEFAULT_ITEM_COUNT);
		while(getItemCount()<itemCount){
			PlayerItem theItem = new PlayerItem(this);
			addItem(theItem);
			theItem.load(thePreferences);
		}
	}

	@Override
	protected void onCommit(Editor theEditor) {
		theEditor.putString(getSubKey(SUBKEY_STATE), getState().name());
		theEditor.putString(getSubKey(SUBKEY_FACING), getFacing().name());
		theEditor.putInt(getSubKey(SUBKEY_X), getX());
		theEditor.putInt(getSubKey(SUBKEY_Y), getY());
		theEditor.putInt(getSubKey(SUBKEY_ITEM_COUNT),getItemCount());
		for(PlayerItem theItem:getItems()){
			theItem.commit(theEditor);
		}		
	}

	private PlayerItem getItem(int theIndex) {
		return getItems().get(theIndex);
	}

	private String getSubKey(String theSubKey) {
		return getKeyPrefix() + theSubKey;
	}

	@Override
	public Context getContext() {
		return getData().getContext();
	}

	public void newGame() {
		Maze mazeData = getData().getMazeData();
		clearData();
		Room theRoom = mazeData.getEntrance();
		setX(theRoom.getX());
		setY(theRoom.getY());
		setFacing(Utilities.randomDirection());
	}

	public void setY(int theY) {
		y = theY;
	}

	public void setX(int theX) {
		x = theX;
	}
	
	public int getX(){
		return x;
	}
	
	public int getY(){
		return y;
	}

	private void clearData() {
		getItems().clear();
	}

	public PlayerState getState() {
		return state;
	}

	public void setState(PlayerState state) {
		this.state = state;
	}

	public GameState getGameStateForPlayerState() {
		return getState().getGameState();
	}

	public RoomDirection getFacing() {
		return facing;
	}

	public void setFacing(RoomDirection facing) {
		this.facing = facing;
	}

	public boolean turnAround() {
		setFacing(getFacing().opposite());
		return true;
	}

	public boolean turnRight() {
		setFacing(getFacing().next());
		return true;
	}

	public boolean turnLeft() {
		setFacing(getFacing().previous());
		return true;
	}

	public MoveAheadResult moveAhead() {
		Door theDoor = getData().getMazeData().getRoom(getX(), getY()).getDoor(getFacing());
		if(theDoor.getDoorState().isPassable()){
			setX(getFacing().nextColumn(getX(), getY()));
			setY(getFacing().nextRow(getX(), getY()));
			return MoveAheadResult.SUCCESS;
		}else{
			switch(theDoor.getDoorState()){
			case CLOSED_DOOR:
				return MoveAheadResult.DOOR_CLOSED;
			case LOCKED_DOOR:
				return MoveAheadResult.DOOR_LOCKED;
			default:
				return MoveAheadResult.IMPASSABLE;
			}
		}
	}

	public CloseDoorActionResult closeDoor() {
		Door theDoor = getData().getMazeData().getRoom(getX(), getY()).getDoor(getFacing());
		switch(theDoor.getDoorState()){
		case OPEN_DOOR:
			theDoor.setDoorState(DoorState.CLOSED_DOOR);
			theDoor.getData().getNeighbor(getFacing()).getDoor(getFacing().opposite()).setDoorState(DoorState.CLOSED_DOOR);
			return CloseDoorActionResult.SUCCESS;
		case CLOSED_DOOR:
		case LOCKED_DOOR:
			return CloseDoorActionResult.ALREADY_CLOSED;
		default:
			return CloseDoorActionResult.NO_DOOR_TO_CLOSE;
		}
	}

	public OpenDoorActionResult openDoor() {
		Door theDoor = getData().getMazeData().getRoom(getX(), getY()).getDoor(getFacing());
		switch(theDoor.getDoorState()){
		case CLOSED_DOOR:
			theDoor.setDoorState(DoorState.OPEN_DOOR);
			theDoor.getData().getNeighbor(getFacing()).getDoor(getFacing().opposite()).setDoorState(DoorState.OPEN_DOOR);
			return OpenDoorActionResult.SUCCESS;
		case OPEN_DOOR:
			return OpenDoorActionResult.ALREADY_OPEN;
		case LOCKED_DOOR:
			return OpenDoorActionResult.DOOR_LOCKED;
		default:
			return OpenDoorActionResult.NO_DOOR_TO_OPEN;
		}
	}

	public Room getCurrentRoom() {
		return getData().getMazeData().getRoom(getX(), getY());
	}

	public TakeItemActionResult takeItem(int itemIndex) {
		Room theRoom = getCurrentRoom();
		RoomItem theItem = theRoom.getRoomItem(itemIndex);
		theRoom.getItems().remove(itemIndex);
		getItems().add(new PlayerItem(this,theItem));
		return TakeItemActionResult.SUCCESS;
	}

	public String getKeyPrefix() {
		return KEY_BASE;
	}

	public void setWallMark(String theWallMark) {
		Door theDoor = getData().getMazeData().getRoom(getX(), getY()).getDoor(getFacing());
		theDoor.setWallMark(theWallMark);
	}

	public UnlockDoorActionResult unlockDoor() {
		Door theDoor = getData().getMazeData().getRoom(getX(), getY()).getDoor(getFacing());
		switch(theDoor.getDoorState()){
		case CLOSED_DOOR:
		case OPEN_DOOR:
			return UnlockDoorActionResult.NO_LOCK_PRESENT;
		case LOCKED_DOOR:
			Iterator<PlayerItem> iterator = getItems().iterator();
			while(iterator.hasNext()){
				PlayerItem item = iterator.next();
				if(item.isKey()){
					if(item.getLockMaterial()==theDoor.getLockMaterial() && item.getLockDetail()==theDoor.getLockDetail()){
						theDoor.setDoorState(DoorState.CLOSED_DOOR);
						theDoor.getData().getNeighbor(getFacing()).getDoor(getFacing().opposite()).setDoorState(DoorState.CLOSED_DOOR);
						getItems().remove(item);
						return UnlockDoorActionResult.SUCCESS;
					}
				}
			}
			return UnlockDoorActionResult.NO_KEY_PRESENT;
		default:
			return UnlockDoorActionResult.NO_DOOR_TO_UNLOCK;
		}
		
	}

	public SearchWallActionResult searchWall() {
		Door theDoor = getData().getMazeData().getRoom(getX(), getY()).getDoor(getFacing());
		if(theDoor.getDoorState().canFind()){
			DoorState theNewDoorState = theDoor.getDoorState().find();
			theDoor.setDoorState(theNewDoorState);
			theDoor.getData().getNeighbor(getFacing()).getDoor(getFacing().opposite()).setDoorState(theNewDoorState);
			return SearchWallActionResult.SUCCESS;
		}else{
			return SearchWallActionResult.NO_SECRET_DOOR;
		}
	}

	public DropItemActionResult dropItem(int theItemIndex) {
		Room theRoom = getCurrentRoom();
		PlayerItem theItem = this.getItem(theItemIndex);
		getItems().remove(theItem);
		theRoom.getItems().add(new RoomItem(theRoom,theItem));
		return DropItemActionResult.SUCCESS;
	}

	public SearchForItemsResult searchForItems() {
		Room theRoom = getCurrentRoom();
		Iterator<RoomItem> iterator = theRoom.getItems().iterator();
		int theCount = 0;
		while(iterator.hasNext()){
			RoomItem theItem = iterator.next();
			if(theItem.isHidden()){
				theCount++;
				theItem.setHidden(false);
			}
		}
		if(theCount>0){
			return SearchForItemsResult.SUCCESS;
		}else{
			return SearchForItemsResult.NO_ITEMS_FOUND;
		}
	}
}
